package com.wf.service.impl;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wf.constant.RedisConstant;
import com.wf.context.BaseContext;
import com.wf.domain.*;
import com.wf.dto.Houses_facility_DTO;
import com.wf.dto.PageDTO;
import com.wf.mapper.*;
import com.wf.service.HousesInfoService;
import com.wf.utils.RedisUtil;
import com.wf.vo.HouseDetailsPageVO;
import com.wf.vo.HouseDetailsVO;
import com.wf.vo.PageQueryVO;
import com.wf.vo.PageResultVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author mpk16
 * @description 针对表【houses_info】的数据库操作Service实现
 * @createDate 2024-08-03 13:39:49
 */
@Service
@Slf4j
public class HousesInfoServiceImpl extends ServiceImpl<HousesInfoMapper, HousesInfo>
        implements HousesInfoService {

    @Autowired
    ApartmentInfoMapper apartmentInfoMapper;

    // 定义合同信息的Mapper接口引用
    @Autowired
    ContractInfoMapper contractInfoMapper;

    // 自动注入房屋信息的Mapper接口
    @Autowired
    HousesInfoMapper housesInfoMapper;

    @Autowired
    MyFavoritesMapper myFavoritesMapper;

    @Autowired
    BookingInfoMapper bookingInfoMapper;

    // 自动注入Redis工具类
    @Autowired
    RedisUtil redisUtil;

    @Override
    public PageResultVO<HouseDetailsPageVO> pageList(PageDTO pageDTO) {
        // 创建一个分页结果对象
        PageResultVO<HouseDetailsPageVO> pageResultVO = new PageResultVO<>();


        // 通过Mapper查询分页列表
        List<HouseDetailsPageVO> list = housesInfoMapper.selectpageList(pageDTO);

        // 设置排序后的列表到结果对象
        pageResultVO.setList(list);
        // 查询未签约房屋的总记录数
        Integer total = contractInfoMapper.selectCount(new LambdaQueryWrapper<ContractInfo>().eq(ContractInfo::getStatus, "0"));
        // 设置总记录数到结果对象
        pageResultVO.setTotal(total);
        // 返回分页结果
        return pageResultVO;
    }

    private List<Integer> getContractIdsFromRedis(String prefix) {
        try {
            Set<String> keys = redisUtil.keys(prefix + "*");
            if (keys == null || keys.isEmpty()) {
                return Collections.emptyList();
            }
            return keys.stream()
                    .map(key -> Integer.parseInt(key.replace(prefix, "")))
                    .collect(Collectors.toList());
        } catch (NumberFormatException e) {
            log.error("Error parsing Redis keys: {}", e.getMessage());
            return Collections.emptyList();
        }
    }


    /**
     * 获取房屋详情
     *
     * @param contractId 合同id
     * @return 房屋详情对象
     */
    @Override
    public HouseDetailsVO getHouseDetail(String contractId) {


        HousesInfoServiceImpl housesInfoService = SpringUtil.getBean(HousesInfoServiceImpl.class);
        HashMap<String, Object> map = housesInfoService.getHouse(contractId);

        // 获取houseDetailsVO并进行类型检查
        Object houseDetailsObj = map.get("houseDetailsVO");
        HouseDetailsVO houseDetailsVO = null;
        if (houseDetailsObj instanceof HouseDetailsVO) {
            houseDetailsVO = (HouseDetailsVO) houseDetailsObj;
        }

        // 获取roomFacility并进行类型检查
        Object roomFacilityObj = map.get("roomFacility");
        List<String> roomFacility = null;
        if (roomFacilityObj instanceof List) {
            roomFacility = (List<String>) roomFacilityObj;
        }

        // 获取energyFacility并进行类型检查
        Object energyFacilityObj = map.get("energyFacility");
        List<String> energyFacility = null;
        if (energyFacilityObj instanceof List) {
            energyFacility = (List<String>) energyFacilityObj;
        }

        // 获取apartmentInfo并进行类型检查
        Object apartmentInfoObj = map.get("apartmentInfo");
        ApartmentInfo apartmentInfo = null;
        if (apartmentInfoObj instanceof ApartmentInfo) {
            apartmentInfo = (ApartmentInfo) apartmentInfoObj;
        }

        // 更新或记录房源的浏览计数
        if (redisUtil.hasKey(RedisConstant.APARTMENT_HOUSE_VIEW_COUNT + contractId)) {
            redisUtil.incr(RedisConstant.APARTMENT_HOUSE_VIEW_COUNT + contractId, 1);
        } else {
            redisUtil.set(RedisConstant.APARTMENT_HOUSE_VIEW_COUNT + contractId, 1);
        }
        // 将房源详情添加到当前用户的历史记录中，使用当前时间戳作为分数
        redisUtil.zSet(RedisConstant.APARTMENT_HISTORY_LIST + BaseContext.getCurrentId(), houseDetailsVO,
                LocalDateTimeUtil.toEpochMilli(LocalDateTime.now()));

        BeanUtils.copyProperties(apartmentInfo, houseDetailsVO);
        // 设置设施信息到房屋详情对象
        houseDetailsVO.setRoomFacility(roomFacility);
        houseDetailsVO.setEnergyFacility(energyFacility);

        // 查询当前用户是否收藏了该房屋
        LambdaQueryWrapper<MyFavorites> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(MyFavorites::getUserId, BaseContext.getCurrentId())
                .eq(MyFavorites::getContractId, contractId);
        MyFavorites favorites = myFavoritesMapper.selectOne(wrapper);

        // 查询当前用户是否预订了该房屋
        LambdaQueryWrapper<BookingInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(BookingInfo::getUserId, BaseContext.getCurrentId())
                .eq(BookingInfo::getHouseId, houseDetailsVO.getHousesId());
        BookingInfo booking = bookingInfoMapper.selectOne(queryWrapper);

        // 设置房屋的收藏状态
        houseDetailsVO.setIsCollect(favorites != null);

        // 设置房屋的预订状态
        houseDetailsVO.setIsBooking(booking != null);

        houseDetailsVO.setBookingInfo(booking);
        // 返回房屋详情
        return houseDetailsVO;
    }

    /**
     * 根据用户ID查询已签约的房屋
     *
     * @param userId 用户ID
     * @return 已签约房屋列表
     */
    @Override
    public List<HouseDetailsVO> getHouseByUserId(Long userId) {
        // 查询该用户的所有合同信息
        List<ContractInfo> contractInfos = contractInfoMapper.selectList(new LambdaQueryWrapper<ContractInfo>().eq(ContractInfo::getUserId, userId));
        // 定义已签约房屋详情列表
        ArrayList<HouseDetailsVO> houseDetailsVOS = null;
        // 如果合同信息列表不为空且不为空
        if (contractInfos != null && !contractInfos.isEmpty()) {
            houseDetailsVOS = new ArrayList<>();
            // 遍历合同信息列表
            for (ContractInfo contractInfo : contractInfos) {
                // 创建房屋详情对象
                HouseDetailsVO houseDetailsVO = new HouseDetailsVO();
                // 如果合同状态为已签约
                if (contractInfo.getStatus() == 1) {
                    // 通过合同关联的房屋ID获取房屋信息
                    HousesInfo housesInfo = this.getById(contractInfo.getHouseId());
                    // 将housesInfo和contractInfo的属性复制到houseDetailsVO
                    BeanUtils.copyProperties(housesInfo, houseDetailsVO);
                    BeanUtils.copyProperties(contractInfo, houseDetailsVO);
                    // 将房屋详情对象添加到列表
                    houseDetailsVOS.add(houseDetailsVO);
                }
            }
        }
        // 返回已签约房屋列表
        return houseDetailsVOS;
    }

    /**
     * 根据条件分页查询房屋信息
     *
     * @param vo 分页查询参数对象
     * @return 分页查询结果
     */
    @Transactional(readOnly = true)
    @Override
    public Page<HousesInfo> findPage(PageQueryVO vo) {
        // 如果分页查询参数对象为空，则返回null
        if (ObjectUtil.isEmpty(vo)) {
            return null;
        }
        // 获取分页参数中的当前页码和每页记录数
        Integer currentPage = vo.getCurrentPage();
        Integer pageSize = vo.getPageSize();
        String queryString = vo.getQueryString();

        // 封装Page对象
        Page<HousesInfo> page = new Page<>(currentPage, pageSize);
        // 封装查询条件
        LambdaQueryWrapper<HousesInfo> queryWrapper = new LambdaQueryWrapper<>();
        // 设置查询条件
        queryWrapper.or().eq(StringUtils.hasLength(queryString), HousesInfo::getHousesId, queryString);

        // 执行分页查询
        Page<HousesInfo> resultPage = this.baseMapper.selectPage(page, queryWrapper);
        // 返回查询结果
        return resultPage;
    }

    @Override
    public Houses_facility_DTO selectAllFacilityByHousesId(Long houses_id) {
        return housesInfoMapper.selectAllFacilityByHousesId(houses_id);
    }

    // 内部辅助方法：根据设施类型过滤房屋设施
    private List<String> filterFacility(List<Map<String, Object>> houseFacility, String facilityType) {
        return houseFacility.stream()
                .filter(facility -> StrUtil.equals(facility.get("facility_type").toString(), facilityType))
                .map(facility -> facility.get("facility_name").toString())
                .collect(Collectors.toList());
    }

    @NotNull
    @Cacheable(value = "house", key = "#contractId")
    public HashMap<String, Object> getHouse(String contractId) {

        // 通过合同ID获取合同信息
        ContractInfo contractInfo = contractInfoMapper.selectById(contractId);
        // 通过房屋ID获取房屋信息
        HousesInfo housesInfo = this.getById(contractInfo.getHouseId());
        // 获取房屋设施信息
        List<Map<String, Object>> houseFacility = housesInfoMapper.getHouseFacility(contractInfo.getHouseId());

        // 分别处理并获取卧室设施和能源设施列表
        List<String> roomFacility = filterFacility(houseFacility, "1");
        List<String> energyFacility = filterFacility(houseFacility, "2");

        // 获取公寓信息
        ApartmentInfo apartmentInfo = apartmentInfoMapper.selectById(housesInfo.getApartmentId());
        // 创建房屋详情对象
        HouseDetailsVO houseDetailsVO = new HouseDetailsVO();
        // 将housesInfo、contractInfo和apartmentInfo的属性复制到houseDetailsVO
        BeanUtils.copyProperties(housesInfo, houseDetailsVO);
        BeanUtils.copyProperties(contractInfo, houseDetailsVO);

        HashMap<String, Object> map = new HashMap<>();
        map.put("houseDetailsVO", houseDetailsVO);
        map.put("apartmentInfo", apartmentInfo);
        map.put("roomFacility", roomFacility);
        map.put("energyFacility", energyFacility);

        return map;
    }

}



